{///////////////////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2007 Ksana Search Forge. All rights reserved.
//
// This file is part of the KsanaCore module of the Ksana Search Engine.
//
// This file may be used under the terms of the GNU General Public
// License version 3.0 as published by the Free Software Foundation
// and appearing in the file gpl-3.0.txt included in the packaging of
// this file.  Please review the following information to ensure GNU
// General Public Licensing requirements will be met:
// http://license.ksana.tw/opensource/
//
// If you are unsure which license is appropriate for your use, please
// review the following information:
// http://license.ksana.tw/
// or contact our business representative ksanaservice@gmail.com
//
// Ksana Search Forge reserves all rights not expressly granted herein.
// 
// Ksana Search Forge (c) 2007
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
///////////////////////////////////////////////////////////////////////////////////////////////}

unit tempfile;

interface
uses classes,sysutils;

const
  FLUSH_TERMINATOR = int64(-1);
var
_temp:TFileStream;
tempfilename:string;
//availmemory:cardinal;
slflushed:Tstringlist;

//caller is responsible to provide the previous saved location
function writetempblock(const data:pchar;size:cardinal;prevlocation:int64):int64;

//
function mergetempblock(const flushptr:int64;const data:pchar;size:cardinal;
var outputdata:pchar;var outputsize:cardinal):integer;
procedure inittemp(tf:string);
procedure finalizetemp;

implementation

{*------------------------------------------------------------------------------
  structure of temporary block
  previous location: int64
  size of the tempbloc: integer
  tempblock

  @param rm   ParameterDescription
  @param prevlocation   ParameterDescription
  @return ResultDescription  
------------------------------------------------------------------------------*}
function writetempblock(const data:pchar;size:cardinal;prevlocation:int64):int64;
begin
  result:=_temp.Position ;

  _temp.Write(prevlocation ,sizeof(prevlocation) );
  _temp.write(size, sizeof(size));
  if size=0 then begin
    exit;
    raise exception.create('empty rm.size');
  end;
	_temp.write(data^,size);
end;


{
merge temp block in disk and memory block in rm,
into a new memory block return by rm.
caller is responsible to free the memory up.
}

function mergetempblock(const flushptr:int64;const data:pchar;size:cardinal;
                        var outputdata:pchar;var outputsize:cardinal):integer;
var
	mergedptr,ptr:Pchar;
	fp,savepos:int64;
  totalsize,sz:cardinal;
begin
  fp:=flushptr;
  totalsize:=size;

	savepos:=_temp.position;

//adding up temp block size
	while (fp<>FLUSH_TERMINATOR) do begin
    if fp>_temp.size then begin
      exit;
      break;
      raise exception.create('error temp position');
    end;
		_temp.position:=fp;
    _temp.read(fp,sizeof(fp));
    _temp.read(sz,sizeof(size));

  	inc(totalsize,sz);
  end;

//now we got the totalsize, allocate a new buffer
//  if totalsize>availmemory then begin
//    exit;
//    raise exception.create('not enough memory');
//  end;
	getmem(mergedptr,totalsize);

	ptr:=mergedptr;

	//copy the object data in memory
	inc(ptr , (totalsize- size));
	move(data^,ptr^,size);

	fp:=flushptr;
	while (fp<>FLUSH_TERMINATOR) do begin
    if fp>_temp.size then begin
      raise exception.create('error temp position');
    end;
		_temp.position:=fp;
    _temp.read(fp,sizeof(fp));
    _temp.read(sz,sizeof(size));
		dec(ptr,sz);
    _temp.read(ptr^,sz);
	end;

	//retored position
	_temp.position:=savepos;


	outputdata:=mergedptr;
	outputsize:=totalsize;

end;

procedure inittemp(tf:string);
begin
  if assigned(_temp) then begin
    raise exception.create('already using '+tempfilename+' as tempfile');
    exit;
  end;
  _temp:=TFilestream.create(tf,fmcreate);
  _temp.free;
  _temp:=TFilestream.create(tf,fmopenreadwrite or fmsharedenywrite);

  tempfilename:=tf;

  slflushed:=tstringlist.create;
end;

procedure finalizetemp;
begin
  if assigned(_temp) then begin
    _temp.free;
    _temp:=nil;
  end else begin
    raise exception.create('no temp file');
  end;
  if fileexists(tempfilename) then deletefile(tempfilename);
  if assigned(slflushed) then slflushed.free;

end;

end.
